#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <dlfcn.h>

#include "loadkeys.h"
#include "hashmap.h"
#include "socproof.h"

#include <vector>
#include <map>
#include <list>

#define PUBFILE   "pubkey0.pem"
#define PRIVFILE  "privkey0.pem"
#define STDIN     0
#define STDOUT    1
#define RAND() (lrand48())
#define SEED(s) (srand48(s))
#define G_MAX 200

#define STRINGLEN 100

using namespace std;

int keysize = 0;

unsigned char* gen_hash(char * key, unsigned int *len)
{
    EVP_MD_CTX mdctx;
    const EVP_MD *md;
    unsigned char *md_value;

    md_value = (unsigned char *)malloc(EVP_MAX_MD_SIZE);
    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sha1");

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, key, strlen(key));
    EVP_DigestFinal_ex(&mdctx, md_value, len);
    EVP_MD_CTX_cleanup(&mdctx);

    return md_value;
}

unsigned char* bin_hash(unsigned char * key, int *len)
{
    EVP_MD_CTX mdctx;
    const EVP_MD *md;
    unsigned char *md_value;

    md_value = (unsigned char *)malloc(EVP_MAX_MD_SIZE);
    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("sha1");

    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, key, *len);
    EVP_DigestFinal_ex(&mdctx, md_value, (unsigned int *)len);
    EVP_MD_CTX_cleanup(&mdctx);

    return md_value;
}


void hexdump(unsigned char *s,int len)
{
    int n=0;
    for(n=0 ; n < len ; ++n)
    {
        if((n%16) == 0)
            fprintf(stderr,"\n%04x",n);
        fprintf(stderr," %02x",s[n]);
    }
    fprintf(stderr,"\n");
}

// load the private key, generate the hash of the text and sign it with private key
unsigned char* generate_certificate(char *cleartext, int *cert_len, char *privKeyFile)
{
    EVP_PKEY *privKey;
    ERR_load_crypto_strings();

    privKey = ReadPrivateKey(privKeyFile);
    if (!privKey)
    {
        EVP_PKEY_free(privKey);
        fprintf(stderr, "error loading private key \n");
        exit (1);
    }

    int keylen = EVP_PKEY_size(privKey);
    if (keysize == 0)
    {
        keysize = keylen;
    }
    unsigned char *certificate = (unsigned char*) malloc(EVP_PKEY_size(privKey));

    unsigned char *hash;
    unsigned int hash_len = 20;
    hash = gen_hash(cleartext, &hash_len);

    *cert_len = RSA_private_encrypt(hash_len, hash, certificate, privKey->pkey.rsa, RSA_PKCS1_PADDING);

    if (*cert_len!= keylen)
    {
        fprintf(stderr,"Error: ciphertext should match length of key\n");
        exit(1);
    }

    free(hash);
    EVP_PKEY_free(privKey);
    return certificate;
}

int verify_certificate(char *cleartext, unsigned char *certificate, int certLen, char *pubKeyFile)
{
    EVP_PKEY *pubKey;
    ERR_load_crypto_strings();

    pubKey = myReadPublicKey(pubKeyFile);
    if(!pubKey)
    {
        EVP_PKEY_free(pubKey);
        fprintf(stderr,"Error: can't load public key\n");
        exit(1);
    }

    int keylen = EVP_PKEY_size(pubKey);
    unsigned char *verifiedHash = (unsigned char *) malloc(keylen); // this cant be greater than the hashlen.. but just to be safe
    unsigned int hash_len = 20;
    unsigned char *hash = gen_hash(cleartext, &hash_len);

    // no need to store the length of the hash recovered
    RSA_public_decrypt(certLen, certificate, verifiedHash, pubKey->pkey.rsa, RSA_PKCS1_PADDING);

    if (memcmp(hash, verifiedHash, hash_len) == 0)
    {
    }
    else
    {
        printf("FAILED\n");
        exit(1);
    }

    free(verifiedHash);
    EVP_PKEY_free(pubKey);
    free(hash);

    return 1;
}


// generate and return some random string
char* getRandomString(int len)
{
    char *retString = (char *)malloc(len+1);
    int j =0;

    for(j = 0; j < len; j++)
    {
        retString[j] = (char)(97 + RAND()%26);
    }
    *(retString+len) = '\0';

    return retString;
}

void ltoa(char *a, long l, size_t length)
{
    char temp[100];

    sprintf(temp, "%ld", l);
    strncpy(a, temp, length);
}

char* readFileBytes(const char *name)
{
    FILE *fl = fopen(name, "r");
    int c = 0;
    while (fgetc(fl) != EOF)
        c++;
    fclose(fl);
    int len = c;
    char *ret = (char*) malloc(len+1);
    fl = fopen(name, "r");
    c = 0;
    char ch = 0;
    while ((ch=fgetc(fl)) != EOF)
        ret[c++] = ch;
    ret[c] = '\0';
    fclose(fl);
    return ret;
}

void writeFileBytes(const char *name, char *byte)
{
    FILE *fl = fopen(name, "w");
    fwrite (byte, 1 , strlen(byte), fl);
    fclose (fl);
}




void *friend_hash[G_MAX];
vector<transact_proof *> server_hash[G_MAX];
multimap<int,int> friend_list;
vector<int> his_friends;
vector<int> his_opins;

struct user_hashes hash_l[G_MAX];

//Time cost calculation variables
static double avg_tp_ec, avg_fp_ec, avg_tp_ec_t, avg_fp_ec_t;
static double avg_tp_dc, avg_fp_dc, avg_tp_dc_t, avg_fp_dc_t;
static double f_proof_size, f_proof_t;
static double t_proof_size, t_proof_t;
static double h_proof_size, h_proof_t;
static double avg_mob_com;
static double tp_hash;

int main(int argc, char* argv[])
{
    struct timeval tm;
    gettimeofday(&tm,NULL);
    SEED(tm.tv_sec+tm.tv_usec);


    graph_function_one(argv[1],argv[2]);

    init_file_read(); //Function to read the file specifying the no. of friends and opinions

    init_friendship_graph(); //Friendhip proofs and graph generated
    init_transaction_graph(); //Each user goes and sumbit about 5-10 opinions

    //Creating a sample case when user "4" goes to the center and enquires for opinions of all his friends"
    test_case();

    test_case2();

/*    //Log
    printf("\n\no-----------------------o");
    printf("\n|Avg transaction/hash proof creation time:%lf",avg_tp_ec/avg_tp_ec_t);
    printf("\n|Avg friendship proof creation time:%lf",avg_fp_ec/avg_fp_ec_t);
    printf("\n|Avg transaction/hash proof verify time:%lf",avg_tp_dc/avg_tp_dc_t);
    printf("\n|Avg friendship proof verify time:%lf",avg_fp_dc/avg_fp_dc_t);
    printf("\n|Avg friendship proof bandwidth:%lf Bytes",(f_proof_size/f_proof_t)/8);
    printf("\n|Avg transaction proof bandwidth:%lf Bytes",(t_proof_size/t_proof_t)/8);
    printf("\n|Avg hash exchange bandwidth:%lf Bytes",(h_proof_size/h_proof_t)/8);
    printf("\n|Total no. of queries served:%lf",avg_fp_ec_t); //Write in a file //append
    printf("\n|Total amount of time taken:%lf",avg_fp_ec+avg_tp_ec); //Write in a file "
    printf("\no-----------------------o\n");
*/

    //Also write the no. of friends and opinions along side "


    FILE *fl = fopen("no_friends", "a");
    fwrite (argv[1], 1 , strlen(argv[1]), fl);
    fwrite ("\n", 1 , strlen("\n"), fl);
    fclose (fl);

    //FILE *fl = fopen("no_friends", "a");
    double va=(G_MAX)/(avg_fp_dc+tp_hash);
    double va1=(G_MAX)/(avg_mob_com);
    //printf("%s server: %lf client: %lf\n",argv[1],va,va1);
    //fwrite (va, 1 , sizeof, fl);
    //fclose (fl);

    //on the mobile side

    return 0;
}


void test_case2() {

double static time_taken;
double static time_taken2;

struct timeval tm;

    for(int i=0; i<1000; i++) {


        gettimeofday(&tm, NULL);
        double first = tm.tv_sec + tm.tv_usec/1000000.00;
        create_friend_proofs(1,2);
        gettimeofday(&tm, NULL);
        double second = tm.tv_sec + tm.tv_usec/1000000.00;
        time_taken=second-first;
    }


    for(int i=0; i<1000; i++) {


        gettimeofday(&tm, NULL);
        double first = tm.tv_sec + tm.tv_usec/1000000.00;
        create_transaction_proofs(1,"asdfasdgasfgasfdgasdfgasdfgasd");
        gettimeofday(&tm, NULL);
        double second = tm.tv_sec + tm.tv_usec/1000000.00;
        time_taken2=second-first;
    }


    printf("Friendship proofs: %lf ",time_taken/1000);
    printf("Transaction proofs: %lf ",time_taken2/1000);

}

void graph_function_one(char *friends, char *opinions) {

 //The ang. no. of friends a user has
 //It keeps on increasing from 10 to 150 at an increment of 10
 //y-axis is the no. of quesries the server can process in one second
 //Total amount of time taken by the server to process the queries/functions
 //and each one of them
    //printf("here");
    //Create a file with no. of friends and opinions side by side
    int i;
    int j=atoi(friends);

    FILE *fl = fopen("friend.dat", "w");

    for(i=0;i<G_MAX;i++) {
        fwrite (friends, 1 , strlen(friends), fl);
        fwrite (" ", 1 , strlen(" "), fl);
        fwrite (opinions, 1 , strlen(opinions), fl);
        fwrite ("\n", 1 , strlen("\n"), fl);
    }

    fclose (fl);

}


void init_file_read() {

FILE *file = fopen ( "friend.dat", "r" );
char *pch;

	if ( file != NULL )
	{
		char line [ 128 ]; /* or other suitable maximum line size */

		while ( fgets ( line, sizeof(line), file ) != NULL ) /* read a line */
		{
			pch=strtok(line," ");
			his_friends.push_back(atoi(pch));
			pch=strtok(NULL, " \n");
			his_opins.push_back(atoi(pch));
        }

	fclose ( file );
	}
	else
	{
		perror ( "friend.dat" ); /* why didn't the file open? */
	}


}

//Content pubKeyA, pubKeyB
void test_case()
{
    //Send the proofs of Person "4" to the server
    //The server checks the proof of all the friends of person "4"
    //Before passing on the transaction proof check by encrypting the content of the friend proofs whether they are secure or not

    //int i;
    struct timeval tm;

    unsigned char* new_hash=NULL;
    unsigned int len=0;

    map<int,int>::const_iterator iter;
    for(iter=friend_list.begin(); iter != friend_list.end(); ++iter)
    {
        //Encrypt the content

	//printf("\n%d %d",iter->first,iter->second);
    //    if(iter->first==4) {
            //printf("\n\nFrom friend %d",iter->second);
            struct friend_proof *fp = (struct friend_proof *)hashmap_get(friend_hash[iter->first],iter->second);


            /*Check creation time*/
            gettimeofday(&tm, NULL);
            double first = tm.tv_sec + tm.tv_usec/1000000.00;

            int is_fr_temp=is_friend(fp,iter->first);

            gettimeofday(&tm, NULL);
            double second = tm.tv_sec + tm.tv_usec/1000000.00;
            avg_fp_dc = avg_fp_dc + second - first;
            avg_fp_dc_t++;
            //Check whether the friendship is true
            if(is_fr_temp)
            {

                //Server sends transaction proofs to user
                int p;
                for(p=0; p < (int)server_hash[iter->second].size(); p++)
                {
                    struct transact_proof *tp = server_hash[iter->second][p];
                    //printf("\nOpinion: %s",tp->content->opin);

                    gettimeofday(&tm, NULL);
                    double first = tm.tv_sec + tm.tv_usec/1000000.00;

                    int is_tm_temp=is_opinion(tp,iter->second);

                    gettimeofday(&tm, NULL);
                    double second = tm.tv_sec + tm.tv_usec/1000000.00;
                    avg_tp_dc = avg_tp_dc + second - first;
                    avg_tp_dc_t++;

                    if(is_tm_temp)
                    {
                        //printf("\nOpinion: %s",tp->content->opin);
                    }

                    //Hash calculation
                    gettimeofday(&tm, NULL);
                    first = tm.tv_sec + tm.tv_usec/1000000.00;

                    new_hash = (unsigned char *)malloc(len+tp->len);
                    memcpy((new_hash+len),tp->encrypt,tp->len);
                    len=tp->len;
                    new_hash = bin_hash(new_hash, &tp->len);

                    gettimeofday(&tm, NULL);
                    second = tm.tv_sec + tm.tv_usec/1000000.00;
                    avg_mob_com = avg_mob_com + second - first;

                }

                if(memcmp(new_hash,hash_l[iter->second].new_hash,hash_l[iter->second].len))
                {
                    //printf("\n$$The server did not cheat$$\n");
                }
                new_hash=NULL;
                len=0;
            }
            //printf("%s",fp->content->publicKeyA);
      //  }

    }
}


int is_opinion(struct transact_proof *TP, int person)
{
    //Decrypt the friend proof using the public key of
    //the person who just sent you the proof

    //Read the users public key
    char privkeyprefix[] = "./key_set//privkey";
    char keysuffix[] = ".pem";
    char pubkeyprefix[] = "./key_set//pubkey";

    EVP_PKEY *pubkey, *privkey;


    char privkeyA[100], pubkeyB[100];
    sprintf(privkeyA, "%s%d%s", privkeyprefix, 4, keysuffix);
    sprintf(pubkeyB, "%s%d%s", pubkeyprefix, person, keysuffix);
    pubkey = myReadPublicKey(pubkeyB);
    privkey = ReadPrivateKey(privkeyA);



    //Generate hash for comparision
    unsigned char *hash;
    unsigned int hash_len;
    unsigned char *buf2 =(unsigned char*)  malloc(EVP_PKEY_size(privkey));


    char dbuffer[33];
    ltoa(dbuffer, (long)TP->content->timeval, 16);

    char *temp_c=NULL;
    temp_c=(char*)malloc(strlen(TP->content->publicKeyA)+strlen(TP->content->publicKeyS)+strlen(TP->content->opin)+33);
    strcpy(temp_c,TP->content->publicKeyA);
    strcat(temp_c,TP->content->publicKeyS);
    strcat(temp_c,TP->content->opin);
    strcat(temp_c,dbuffer);

    hash_len = strlen(temp_c);
    hash = gen_hash(temp_c, &hash_len);

    //Encrypt the content sent
    RSA_public_decrypt(TP->len, TP->encrypt, buf2, pubkey->pkey.rsa,RSA_PKCS1_PADDING);

    if (memcmp(hash, buf2, hash_len) == 0)
    {
        return 1;
    }
    return 0;
}

int is_friend(struct friend_proof *FP, int person)
{
    //Decrypt the friend proof using the public key of
    //the person who just sent you the proof

    //Read the users public key
    char privkeyprefix[] = "./key_set//privkey";
    char keysuffix[] = ".pem";
    char pubkeyprefix[] = "./key_set//pubkey";

    EVP_PKEY *pubkey, *privkey;


    char privkeyS[100], pubkeyA[100];
    sprintf(privkeyS, "%s%d%s", privkeyprefix, 1000, keysuffix);
    sprintf(pubkeyA, "%s%d%s", pubkeyprefix, person, keysuffix);
    pubkey = myReadPublicKey(pubkeyA);
    privkey = ReadPrivateKey(privkeyS);

    //Generate hash for comparision
    unsigned char *hash;
    unsigned int hash_len;
    unsigned char *buf2 = (unsigned char*) malloc(EVP_PKEY_size(privkey));


    char dbuffer[33];
    ltoa(dbuffer, (long)FP->content->timeval, 16);

    char *temp_c=NULL;
    temp_c=(char*)malloc(strlen(FP->content->publicKeyA)+strlen(FP->content->publicKeyB)+33);
    strcpy(temp_c,FP->content->publicKeyA);
    strcat(temp_c,FP->content->publicKeyB);
    strcat(temp_c,dbuffer);

    hash_len = strlen(temp_c);
    hash = gen_hash(temp_c, &hash_len);

    //Encrypt the content sent
    RSA_public_decrypt(FP->len, FP->encrypt, buf2, pubkey->pkey.rsa,RSA_PKCS1_PADDING);

    if (memcmp(hash, buf2, hash_len) == 0)
    {
        return 1;
    }
    return 0;
}


void init_transaction_graph()
{
    int i, j;
    char *opinion;
    struct timeval tm;
    // char *opinion="Hellow theer";

    for(i=0;i<(int)his_friends.size();i++)
    {
        for(j=0;j<his_opins[i];j++)
        {
            int LOW = 1;
            int HIGH = 70;
            int st_len=RAND() % (HIGH - LOW + 1) + LOW;

            opinion=getRandomString(st_len);

            /*Time calc for tproof*/
            gettimeofday(&tm, NULL);
            double first = tm.tv_sec + tm.tv_usec/1000000.00;

            struct transact_proof *TProof=create_transaction_proofs(i, opinion);

            gettimeofday(&tm, NULL);
            double second = tm.tv_sec + tm.tv_usec/1000000.00;
            avg_tp_ec = avg_tp_ec + (second - first);
            avg_tp_ec_t++;

            server_hash[i].push_back(TProof);
        }
    }
}


struct transact_proof* create_transaction_proofs(int a, char *op_n)
{
    /*Forming key's file names*/
    char privkeyprefix[] = "./key_set//privkey";
    char keysuffix[] = ".pem";
    char pubkeyprefix[] = "./key_set//pubkey";

    char privkeyA[500], pubkeyS[500], pubkeyA[500];
    sprintf(privkeyA, "%s%d%s", privkeyprefix, a, keysuffix);
    sprintf(pubkeyS, "%s%d%s", pubkeyprefix, 1000, keysuffix);
    sprintf(pubkeyA, "%s%d%s", pubkeyprefix, a, keysuffix);


    /*Forming time values*/
    struct timeval tm;
    gettimeofday(&tm, NULL);
    double first = tm.tv_sec + tm.tv_usec/1000000.00;
    char dbuffer[33];
    ltoa(dbuffer, (long)first, 16);



    /*Forming content */
    char *pubS, *pubA;

    pubS = readFileBytes(pubkeyS);
    pubA = readFileBytes(pubkeyA);


    struct transact_data *content;
    content= (struct transact_data *) malloc(sizeof(struct transact_data));
    content->publicKeyS=pubS;
    content->publicKeyA=pubA;
    content->opin=op_n;
    content->timeval=first;



    //Forming content for encryption
    unsigned char *hash;
    unsigned char *buf;
    unsigned char *buf2;
    EVP_PKEY *pubKey;
    EVP_PKEY *privKey;
    int len;
    unsigned int hash_len;


    ERR_load_crypto_strings();

    privKey = ReadPrivateKey(privkeyA);
    if (!privKey)
    {
        ERR_print_errors_fp (stderr);
        exit (1);
    }

    pubKey = myReadPublicKey(pubkeyA);
    if(!pubKey)
    {
        EVP_PKEY_free(privKey);
        fprintf(stderr,"Error: can't load public key\n");
        exit(1);
    }


    buf = (unsigned char*) malloc(EVP_PKEY_size(privKey));
    buf2 = (unsigned char*) malloc(EVP_PKEY_size(privKey));


    char *temp_c=NULL;
    temp_c=(char*)malloc(strlen(pubA)+strlen(pubS)+strlen(op_n)+33);
    strcpy(temp_c,content->publicKeyA);
    strcat(temp_c,content->publicKeyS);
    strcat(temp_c,content->opin);
    strcat(temp_c,dbuffer);

    hash_len = strlen(temp_c);
    hash = gen_hash(temp_c, &hash_len);

    //Generating encrypted data
    len = RSA_private_encrypt((int)hash_len, hash, buf, privKey->pkey.rsa,RSA_PKCS1_PADDING);


    if (len != EVP_PKEY_size(pubKey))
    {
        fprintf(stderr,"Error: ciphertext should match length of key\n");
        exit(1);
    }

    //Forming hash values


    //Done

    /* Verification
       RSA_public_decrypt(len, buf, buf2, pubKey->pkey.rsa,RSA_PKCS1_PADDING);
       if (memcmp(hash, buf2, hash_len) == 0)
       {
       printf("Signature verified \n");
       }
       */

    //Preparing transaction proof
    struct transact_proof *proof=NULL;
    proof=(struct transact_proof *)malloc(sizeof(struct transact_proof));
    proof->content = content;
    proof->encrypt = buf;
    proof->len=len;

    t_proof_size=t_proof_size+(len+sizeof(unsigned int)+sizeof(temp_c));
    t_proof_t++;

    gettimeofday(&tm, NULL);
    first = tm.tv_sec + tm.tv_usec/1000000.00;

    unsigned char *temp_buf = buf;
    hash_l[a].new_hash = (unsigned char *)malloc(len+hash_l[a].len);
    memcpy((hash_l[a].new_hash+hash_l[a].len),temp_buf,len);
    hash_l[a].len=len;
    hash_l[a].new_hash = bin_hash(hash_l[a].new_hash, &len);

    gettimeofday(&tm, NULL);
    double second = tm.tv_sec + tm.tv_usec/1000000.00;
    tp_hash = tp_hash + second - first;

    h_proof_size=h_proof_size+(len+sizeof(unsigned int));
    h_proof_t++;

    return proof;

}

/*Each user forming frindships with any random n friends*/
void init_friendship_graph()
{
    int i, j;

//    total_users=(int)(*argv[1]);
    for(i=0;i<(int)his_friends.size();i++)
    {
        list<int> check_no_repeat;

        int a=i;
        friend_hash[a] = hashmap_new(his_friends[i]);
        for(j=0; j<his_friends[i]; j++)
        {
	    //printf("$$%d ",his_friends[i]);

            int LOW = 0;
            int HIGH = his_friends.size()-1;
            int b=RAND() % (HIGH - LOW + 1) + LOW;

            list<int>::iterator iter;
            for(iter=check_no_repeat.begin(); iter != check_no_repeat.end(); iter++) {
                if(*iter==b) {
                    b=RAND() % (HIGH - LOW + 1) + LOW;
                    iter=check_no_repeat.begin();
                }
            }

                check_no_repeat.push_back(b);
                fill_hash(a,b);
                friend_list.insert(pair<int,int>(a,b));

        }
    }
}

void fill_hash(int a, int b)
{
    struct timeval tm;
    /*Friendship proof creation time*/
    gettimeofday(&tm, NULL);
    double first = tm.tv_sec + tm.tv_usec/1000000.00;

    struct friend_proof *FProof = create_friend_proofs(a,b); //Question?!

    gettimeofday(&tm, NULL);
    double second = tm.tv_sec + tm.tv_usec/1000000.00;
    avg_fp_ec = avg_fp_ec + (second - first);
    avg_fp_ec_t++;

    hashmap_insert((void*)friend_hash[a], (void*)FProof, (unsigned long)b);
}


struct friend_proof* create_friend_proofs(int a, int b)
{
    char privkeyprefix[] = "./key_set//privkey";
    char keysuffix[] = ".pem";
    char pubkeyprefix[] = "./key_set//pubkey";

    /*Formin filenames for public keys*/
    char privkeyA[100], pubkeyB[100], pubkeyA[100];
    sprintf(privkeyA, "%s%d%s", privkeyprefix, a, keysuffix);
    sprintf(pubkeyB, "%s%d%s", pubkeyprefix, b, keysuffix);
    sprintf(pubkeyA, "%s%d%s", pubkeyprefix, a, keysuffix);

    /*Forming time values*/
    struct timeval tm;
    gettimeofday(&tm, NULL);
    double first = tm.tv_sec + tm.tv_usec/1000000.00;
    char dbuffer[33];
    ltoa(dbuffer, (long)first, 16);


    //Reading keys from the file
    char *pubB, *pubA;
    pubB = readFileBytes(pubkeyB);
    pubA = readFileBytes(pubkeyA);

    //Forming the content structure
    struct friend_data *content;
    content= (struct friend_data *) malloc(sizeof(struct friend_data));
    content->publicKeyB=pubB;
    content->publicKeyA=pubA;
    content->timeval=first;


    //Forming the Friendship proof containinf both the content and the proof

    unsigned char *hash;
    unsigned char *buf;
    unsigned char *buf2;
    EVP_PKEY *pubKey;
    EVP_PKEY *privKey;
    int len;
    unsigned int hash_len;


    ERR_load_crypto_strings();

    privKey = ReadPrivateKey(privkeyA);
    if (!privKey)
    {
        ERR_print_errors_fp (stderr);
        exit (1);
    }

    pubKey = myReadPublicKey(pubkeyA);
    if(!pubKey)
    {
        EVP_PKEY_free(privKey);
        fprintf(stderr,"Error: can't load public key\n");
        exit(1);
    }


    buf = (unsigned char*)malloc(EVP_PKEY_size(privKey));
    buf2 = (unsigned char*)malloc(EVP_PKEY_size(privKey));  //For checking after decryption


    //Forming the char *content for encryption

    char *temp_c=NULL;
    temp_c=(char *)malloc(strlen(pubA)+strlen(pubB)+33);
    strcpy(temp_c,content->publicKeyA);
    strcat(temp_c,content->publicKeyB);
    strcat(temp_c,dbuffer);

    //Ends here


    hash_len = strlen(temp_c);
    hash = gen_hash(temp_c, &hash_len);

    //Forming the encrypted data
    len = RSA_private_encrypt((int)hash_len, hash, buf, privKey->pkey.rsa,RSA_PKCS1_PADDING);

    if (len != EVP_PKEY_size(pubKey))
    {
        fprintf(stderr,"Error: ciphertext should match length of key\n");
        exit(1);
    }

    //Forming friendship proof and returning
    struct friend_proof *proof=NULL;
    proof=(struct friend_proof *)malloc(sizeof(struct friend_proof));
    proof->content = content;
    proof->encrypt = buf;
    proof->len=len;

    f_proof_size=f_proof_size+(len+sizeof(unsigned int)+strlen(temp_c));
    f_proof_t++;

    return proof;


}

